package com.jair.common.Inteceptor;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import java.text.DateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * SQL执行监听拦截器
 * 监听每个SQL执行并打印最终的SQL语句
 *
 * @author jair
 * @since 2025-01-01
 */
@Slf4j
@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class SqlLogInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        Object parameter = invocation.getArgs()[1];

        // 获取SQL语句
        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
        String sql = boundSql.getSql();

        // 获取参数
        Object parameterObject = boundSql.getParameterObject();
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();

        // 替换SQL中的占位符
        String finalSql = getSql(sql, parameterObject, parameterMappings, mappedStatement.getConfiguration());

        // 格式化SQL语句，使其更易读
        String formattedSql = formatSql(finalSql);

        // 打印最终执行的SQL
        log.info("=== SQL执行监听 ===");
        log.info("执行方法: {}", invocation.getMethod().getName());
        log.info("SQL语句:");
        log.info(formattedSql);
        log.info("参数: {}", parameterObject);
        log.info("==================");

        // 记录执行开始时间
        long startTime = System.currentTimeMillis();

        try {
            // 执行原始方法
            Object result = invocation.proceed();

            // 计算执行时间
            long endTime = System.currentTimeMillis();
            long costTime = endTime - startTime;

            log.info("=== SQL执行完成 ===");
            log.info("执行时间: {}ms", costTime);
            log.info("==================");

            return result;
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            long costTime = endTime - startTime;

            log.error("=== SQL执行异常 ===");
            log.error("执行时间: {}ms", costTime);
            log.error("异常信息: {}", e.getMessage(), e);
            log.error("==================");

            throw e;
        }
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 可以在这里设置一些配置属性
    }

    /**
     * 格式化SQL语句，使其更易读
     *
     * @param sql 原始SQL
     * @return 格式化后的SQL
     */
    private String formatSql(String sql) {
        if (sql == null || sql.trim().isEmpty()) {
            return sql;
        }

        // 移除多余的空格和换行
        sql = sql.replaceAll("\\s+", " ");
        sql = sql.trim();

        // 格式化SELECT语句
        if (sql.toUpperCase().startsWith("SELECT")) {
            sql = formatSelectSql(sql);
        }

        // 格式化INSERT语句
        else if (sql.toUpperCase().startsWith("INSERT")) {
            sql = formatInsertSql(sql);
        }

        // 格式化UPDATE语句
        else if (sql.toUpperCase().startsWith("UPDATE")) {
            sql = formatUpdateSql(sql);
        }

        // 格式化DELETE语句
        else if (sql.toUpperCase().startsWith("DELETE")) {
            sql = formatDeleteSql(sql);
        }

        return sql;
    }

    /**
     * 格式化SELECT语句
     */
    private String formatSelectSql(String sql) {
        // 将SELECT字段分行显示
        sql = sql.replaceAll("(?i)SELECT\\s+", "SELECT\n  ");
        sql = sql.replaceAll("(?i)\\s+FROM\\s+", "\nFROM\n  ");
        sql = sql.replaceAll("(?i)\\s+WHERE\\s+", "\nWHERE\n  ");
        sql = sql.replaceAll("(?i)\\s+AND\\s+", "\n  AND ");
        sql = sql.replaceAll("(?i)\\s+OR\\s+", "\n  OR ");
        sql = sql.replaceAll("(?i)\\s+ORDER BY\\s+", "\nORDER BY\n  ");
        sql = sql.replaceAll("(?i)\\s+GROUP BY\\s+", "\nGROUP BY\n  ");
        sql = sql.replaceAll("(?i)\\s+HAVING\\s+", "\nHAVING\n  ");
        sql = sql.replaceAll("(?i)\\s+LIMIT\\s+", "\nLIMIT\n  ");

        return sql;
    }

    /**
     * 格式化INSERT语句
     */
    private String formatInsertSql(String sql) {
        sql = sql.replaceAll("(?i)INSERT\\s+INTO\\s+", "INSERT INTO\n  ");
        sql = sql.replaceAll("(?i)\\s+VALUES\\s+", "\nVALUES\n  ");
        return sql;
    }

    /**
     * 格式化UPDATE语句
     */
    private String formatUpdateSql(String sql) {
        sql = sql.replaceAll("(?i)UPDATE\\s+", "UPDATE\n  ");
        sql = sql.replaceAll("(?i)\\s+SET\\s+", "\nSET\n  ");
        sql = sql.replaceAll("(?i)\\s+WHERE\\s+", "\nWHERE\n  ");
        sql = sql.replaceAll("(?i)\\s+AND\\s+", "\n  AND ");
        sql = sql.replaceAll("(?i)\\s+OR\\s+", "\n  OR ");
        return sql;
    }

    /**
     * 格式化DELETE语句
     */
    private String formatDeleteSql(String sql) {
        sql = sql.replaceAll("(?i)DELETE\\s+FROM\\s+", "DELETE FROM\n  ");
        sql = sql.replaceAll("(?i)\\s+WHERE\\s+", "\nWHERE\n  ");
        sql = sql.replaceAll("(?i)\\s+AND\\s+", "\n  AND ");
        sql = sql.replaceAll("(?i)\\s+OR\\s+", "\n  OR ");
        return sql;
    }

    /**
     * 获取完整的SQL语句（替换占位符）
     *
     * @param sql 原始SQL
     * @param parameterObject 参数对象
     * @param parameterMappings 参数映射
     * @param configuration MyBatis配置
     * @return 完整的SQL语句
     */
    private String getSql(String sql, Object parameterObject, List<ParameterMapping> parameterMappings, Configuration configuration) {
        if (parameterMappings == null || parameterMappings.isEmpty()) {
            return sql;
        }

        TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
        StringBuilder finalSql = new StringBuilder();

        // 使用正则表达式匹配占位符
        String regex = "\\?";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(sql);

        int paramIndex = 0;
        while (matcher.find() && paramIndex < parameterMappings.size()) {
            ParameterMapping parameterMapping = parameterMappings.get(paramIndex);
            Object value;
            String propertyName = parameterMapping.getProperty();
            if (parameterObject == null) {
                value = null;
            } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                value = parameterObject;
            } else {
                MetaObject metaObject = configuration.newMetaObject(parameterObject);
                value = metaObject.getValue(propertyName);
            }

            // 格式化参数值
            String paramValue = formatParameter(value);
            finalSql.append(sql.substring(0, matcher.start())).append(paramValue);
            sql = sql.substring(matcher.end());
            matcher = pattern.matcher(sql);
            paramIndex++;
        }
        finalSql.append(sql);

        return finalSql.toString();
    }

    /**
     * 格式化参数值
     *
     * @param parameter 参数值
     * @return 格式化后的参数值
     */
    private String formatParameter(Object parameter) {
        if (parameter == null) {
            return "NULL";
        }

        if (parameter instanceof String) {
            return "'" + parameter.toString().replace("'", "''") + "'";
        }

        if (parameter instanceof Date) {
            DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA);
            return "'" + formatter.format(parameter) + "'";
        }

        return parameter.toString();
    }
}